home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / package_16-january-2001.zip / Effects / cheapo statistics.cpp < prev    next >
C/C++ Source or Header  |  2000-10-13  |  12KB  |  422 lines

  1. // Copyright (C) Mikko Apo (apo@iki.fi)
  2. // The following code may be used to write free software
  3. // if credit is given to the original author.
  4. // Using it for anything else is not allowed without permission
  5. // from the author.
  6.  
  7. /*
  8.  
  9.   Revision history:
  10.   1.04    Added new statistics item: "Average power"
  11.   1.03  Noticed an error when suggesting volumes when the signal
  12.         is really loud: the machine would suggest values that are
  13.         not in the range of the volume faders. "Please set master
  14.         volume to 21211 [129.35%]."
  15.         Added new statistics item: "Max change", "Max change location"
  16.   1.02    Got a little guilty consciousness because of not obeying
  17.     the WM_READ mode. <thru> now bypasses machine.
  18.   1.01    Fixed zero crossings miscalculation and added some
  19.     more info. Thanks to Tamas for reporting.
  20.   1.0    First release
  21.  
  22. */
  23.  
  24. #include <string.h>
  25. #include <math.h>
  26. #include "../mdk.h"
  27.  
  28. #define miCOMMAND_STRING "Show analysis...\nReset analysis\nAbout..."
  29. #define miMACHINE_NAME "cheapo statistics"
  30. #define miSHORT_NAME "ch.stats"
  31. #define miMACHINE_AUTHOR "Mikko Apo (apo@iki.fi)"
  32. #define miMAX_TRACKS        0
  33. #define miMIN_TRACKS        0
  34. #define miNUMGLOBALPARAMETERS 0
  35. #define miNUMTRACKPARAMETERS 0
  36. #define miNUMATTRIBUTES 0
  37. #define miVERSION "1.04"
  38.  
  39. // Machine's info
  40.  
  41. CMachineInfo const MacInfo = 
  42. {
  43.     MT_EFFECT,MI_VERSION,MIF_DOES_INPUT_MIXING,miMIN_TRACKS,miMAX_TRACKS,
  44.     miNUMGLOBALPARAMETERS,miNUMTRACKPARAMETERS,NULL,miNUMATTRIBUTES,NULL,
  45. #ifdef _DEBUG
  46.     miMACHINE_NAME" [DEBUG]"
  47. #else
  48.     miMACHINE_NAME
  49. #endif
  50.     ,miSHORT_NAME,miMACHINE_AUTHOR,miCOMMAND_STRING
  51. };
  52.  
  53. class miex : public CMDKMachineInterfaceEx
  54. {
  55.  
  56. };
  57.  
  58. class mi : public CMDKMachineInterface
  59. {
  60. public:
  61.     mi();
  62.  
  63.     virtual void Command(int const i);
  64.  
  65.     virtual void MDKInit(CMachineDataInput * const pi);
  66.     virtual bool MDKWork(float *psamples, int numsamples, int const mode);
  67.     virtual bool MDKWorkStereo(float *psamples, int numsamples, int const mode);
  68.     virtual void MDKSave(CMachineDataOutput * const po) { }
  69.  
  70.     public:
  71.     virtual CMDKMachineInterfaceEx *GetEx() { return &ex; }
  72.     virtual void OutputModeChanged(bool stereo);
  73.  
  74.     public:
  75.     miex ex;
  76.  
  77. private:
  78.     void print_amp(char *txt, float num);
  79.     void print_ana1(char *txt, float max,float min);
  80.     void print_suggest(char *txt, float max,float min);
  81.     void print_time(char *txt,unsigned long samples);
  82.     void print_channel(char *txt,float maxlevelfound, float minlevelfound, unsigned long time_maxvalue, unsigned long time_minvalue, double dcsum,double rms,unsigned long zero_cross, double max_change, unsigned long change_time, double avg);
  83.  
  84.     float left_maxlevelfound,left_minlevelfound;
  85.     float right_maxlevelfound,right_minlevelfound;
  86.     double left_dcsum,right_dcsum;
  87.     double left_rms,right_rms;
  88.     double left_avg,right_avg;
  89.     float prev_left,prev_right;
  90.     unsigned long left_zerocross, right_zerocross;
  91.     unsigned long dcnum;
  92.     unsigned long time_left_minvalue,time_left_maxvalue,time_right_minvalue,time_right_maxvalue;
  93.     bool stereo_mode;
  94.     double left_max_change, right_max_change;
  95.     unsigned long time_left_change,time_right_change;
  96. };
  97.  
  98.  
  99. DLL_EXPORTS
  100.  
  101. mi::mi()
  102. {
  103.     GlobalVals = NULL;
  104.     TrackVals = NULL;
  105.     AttrVals = NULL;
  106.  
  107. }
  108.  
  109. // Produces output for analysis
  110.  
  111. void mi::print_amp(char *txt, float num)
  112. {
  113.     sprintf(txt,"%ssample:%+.1f (",txt,num);
  114.     if(num)
  115.     {
  116.       sprintf(txt,"%s%.1fdB; %+.2f%%)",txt,(float)(20.0*log10(fabs(num)/( (num>0)?32767.0:32768.0) )),(float)((100*num)/( (num>0)?32767.0:32768.0)));
  117.     } else
  118.     {
  119.       sprintf(txt,"%s-inf dB; 0.00%%)",txt);
  120.     }
  121.  
  122.     if(num>32767.0||num<-32768.0)
  123.     {
  124.         sprintf(txt,"%s *** Possible clipping ***",txt);
  125.     }
  126.     sprintf(txt,"%s\n",txt);
  127. }
  128.  
  129. void mi::print_suggest(char *txt, float max,float min)
  130. {
  131.     float tmp_max,tmp_maxrange,tmp;
  132.     if(max>32767.0||min<-32768.0)
  133.     {
  134.         if(fabs(max)<fabs(min))
  135.         {
  136.             tmp_max=(float)fabs(min);
  137.             tmp_maxrange=32768.0;
  138.         } else
  139.         {
  140.             tmp_max=(float)fabs(max);
  141.             tmp_maxrange=32767.0;
  142.         }
  143.         sprintf(txt,"%sThe analysed signal exceeds the normal range between -32768.0 and 32767.0\nIt might clip in the following effect and it will clip if connected to master output.\n",txt);
  144.         tmp=(float)16384.0*(tmp_maxrange/tmp_max);
  145.         if((int)tmp)
  146.         {
  147.           sprintf(txt,"%sThe input volume slider of the next machine should be set to under %d [%.2f%%].\n",txt,(int)tmp,(100*tmp)/16384 );
  148.         } else
  149.         {
  150.         // the setting would be out of the range of the slider, print a warning
  151.         sprintf(txt,"%sThe input volume slider of the next machine CAN NOT BE SET to a value that would prevent clipping.\n -> Set it as small as possible (0 mutes the signal).\n",txt,(int)tmp,(100*tmp)/16384 );
  152.         }
  153.         sprintf(txt,"%s",txt);
  154.         tmp=(float)(log10(tmp_maxrange/tmp_max)*((20.0*16384.0)/(-80.0)));
  155.         if(tmp<16384)
  156.         {
  157.         sprintf(txt,"%sThe master output volume slider should have a value over %d [%.2f%%] to prevent clipping.\n",txt,(int)tmp,(100*tmp)/16384);
  158.         } else
  159.         {
  160.         // the setting would be out of the range of the slider, print a warning
  161.         sprintf(txt,"%sThe master output volume slider CAN NOT BE SET to a value that would prevent clipping.\n -> Set it as high as possible (16384 mutes the output).\n",txt,(int)tmp,(100*tmp)/16384);
  162.         }
  163.     } else
  164.     {
  165.         sprintf(txt,"%sThe analysed signal was in the normal range between -32768.0 and 32767.0. \nThere is no need to adjust the volume sliders.\n",txt);
  166.     }
  167. }
  168.  
  169. void mi::print_time(char *txt,unsigned long samples)
  170. {
  171.   unsigned long secs;
  172.   unsigned long samplespersec=pMasterInfo->SamplesPerSec;
  173.   unsigned long samplespertick=pMasterInfo->SamplesPerTick;
  174.   secs=(unsigned int)(samples/samplespersec);
  175.   sprintf(txt,"%s %ld ticks [time: %d:%02d:%02d.%03d (%ld samples)]\n",txt,samples/samplespertick,secs/3600,(secs%3600)/60,secs%60,(1000*(samples%(samplespersec)))/samplespersec,samples);
  176. }
  177.  
  178. void mi::print_channel(char *txt,float maxlevelfound, float minlevelfound, unsigned long time_maxvalue, unsigned long time_minvalue, double dcsum,double rms,unsigned long zero_cross, double max_change, unsigned long change_time, double avg)
  179. {
  180.     sprintf(txt,"%sMax ",txt);
  181.     print_amp(txt,maxlevelfound);
  182.     sprintf(txt,"%sMax value location: at",txt);
  183.     print_time(txt,time_maxvalue);
  184.  
  185.     sprintf(txt,"%sMin ",txt);
  186.     print_amp(txt,minlevelfound);
  187.     sprintf(txt,"%sMin value location: at",txt);
  188.     print_time(txt,time_minvalue);
  189.  
  190.     sprintf(txt,"%sDC Offset (average): %.1f (",txt,dcsum/dcnum);
  191.     if(dcsum/dcnum)
  192.     {
  193.       sprintf(txt,"%s%.1fdB; %+.2f%%)\n",txt,(float)(20.0*log10(fabs(dcsum/(dcnum*32768.0)))),(float)((100*(dcsum/dcnum))/32768.0));
  194.     } else
  195.     {
  196.       sprintf(txt,"%s-inf dB; 0.00%%)\n",txt);
  197.     }
  198.     rms=sqrt(rms/dcnum);
  199.     sprintf(txt,"%sRMS Power: %.1f (",txt,rms);
  200.     if(rms)
  201.     {
  202.       sprintf(txt,"%s%.1fdB; %+.2f%%)\n",txt,(float)(20.0*log10(rms/32768.0)),(float)((100*rms)/32768.0));
  203.     } else
  204.     {
  205.       sprintf(txt,"%s-inf dB; 0.00%%)\n",txt);
  206.     }
  207.     avg=avg/dcnum;
  208.     sprintf(txt,"%sAverage Power: %.1f (",txt,avg);
  209.     if(rms)
  210.     {
  211.       sprintf(txt,"%s%.1fdB; %+.2f%%)\n",txt,(float)(20.0*log10(avg/32768.0)),(float)((100*avg)/32768.0));
  212.     } else
  213.     {
  214.       sprintf(txt,"%s-inf dB; 0.00%%)\n",txt);
  215.     }
  216.     sprintf(txt,"%sZero crossings: %ld (%.2fHz)\n",txt,zero_cross,(float)(zero_cross*pMasterInfo->SamplesPerSec)/(dcnum*2));
  217.     sprintf(txt,"%sMax change: %.1f (",txt,max_change);
  218.     if(rms)
  219.     {
  220.       sprintf(txt,"%s%.1fdB; %+.2f%%)\n",txt,(float)(20.0*log10(max_change/32768.0)),(float)((100*max_change)/32768.0));
  221.       sprintf(txt,"%sMax change location: at",txt);
  222.       print_time(txt,change_time);
  223.     } else
  224.     {
  225.       sprintf(txt,"%s-inf dB; 0.00%%)\n",txt);
  226.     }
  227. }
  228.  
  229. void mi::Command(int const i)
  230. {
  231.     static char txt[2000];
  232.     switch(i)
  233.     {
  234.     case 0:
  235.         if(dcnum)
  236.         {
  237.           sprintf(txt,"Sound analysis:\n\nStatistical data collected:");
  238.           print_time(txt,dcnum);
  239.           if(stereo_mode)
  240.           {
  241.               sprintf(txt,"%s\nLeft channel:\n\n",txt);
  242.               print_channel(txt,left_maxlevelfound,left_minlevelfound,time_left_maxvalue, time_left_minvalue, left_dcsum,left_rms,left_zerocross,left_max_change,time_left_change,left_avg);
  243.               sprintf(txt,"%s\nRight channel:\n\n",txt);
  244.               print_channel(txt,right_maxlevelfound,right_minlevelfound,time_right_maxvalue, time_right_minvalue, right_dcsum,right_rms,right_zerocross,right_max_change,time_right_change,right_avg);
  245.               sprintf(txt,"%s\nVolume slider suggestion based on max and min levels of both channels:\n\n",txt);
  246.               print_suggest(txt,(left_maxlevelfound>right_maxlevelfound)?left_maxlevelfound:right_maxlevelfound,(left_minlevelfound<right_minlevelfound)?left_minlevelfound:right_minlevelfound);
  247.           } else
  248.           {
  249.               sprintf(txt,"%s\nMono signal:\n\n",txt);
  250.               print_channel(txt,left_maxlevelfound,left_minlevelfound,time_left_maxvalue, time_left_minvalue, left_dcsum,left_rms,left_zerocross,left_max_change,time_left_change,left_avg);
  251.               sprintf(txt,"%s\nVolume slider suggestion based on max and min levels:\n\n",txt);
  252.               print_suggest(txt,left_maxlevelfound,left_minlevelfound);
  253.           }
  254.         } else
  255.         {
  256.             sprintf(txt,"*** No sound analysed ***\n");
  257.         }
  258.         pCB->MessageBox(txt);
  259.         break;
  260.     case 1:
  261.         left_maxlevelfound=right_maxlevelfound=-9999999.0;
  262.         left_minlevelfound=right_minlevelfound=9999999.0;
  263.         left_dcsum=right_dcsum=0.0;
  264.         left_rms=right_rms=0.0;
  265.         left_avg=right_avg=0.0;
  266.         dcnum=0;
  267.         time_left_minvalue=time_left_maxvalue=time_right_minvalue=time_right_maxvalue=0;
  268.         prev_left=prev_right=0.0;
  269.         left_zerocross=right_zerocross=0;
  270.         left_max_change=right_max_change=0.0;
  271.         time_left_change=time_right_change=0;
  272.         break;
  273.     case 2:
  274.         pCB->MessageBox(miMACHINE_NAME"\n\nBuild date: "__DATE__"\nVersion: "miVERSION"\nCoded by: "miMACHINE_AUTHOR"\nThanks to Oskari and other #buzz developers.\n\nCheck out http://www.iki.fi/apo/buzz/\nfor more buzz stuff.\n\nExcellent skin made by Hymax.");
  275.         break;
  276.     }
  277. }
  278.  
  279. void mi::MDKInit(CMachineDataInput * const pi)
  280. {
  281.     stereo_mode=false;
  282.     Command(1);
  283. }
  284.  
  285. void mi::OutputModeChanged(bool stereo)
  286. {
  287.     stereo_mode=stereo;
  288.     Command(1);
  289. }
  290.  
  291. bool mi::MDKWorkStereo(float *psamples, int numsamples, int const mode)
  292. {
  293.     float l,r;
  294.     double tmp;
  295.  
  296.     if ((mode==WM_WRITE)||(mode==WM_NOIO))
  297.     {
  298.         return false;
  299.     }
  300.  
  301.     if (mode == WM_READ)        // <thru>
  302.         return true;
  303.  
  304.     do 
  305.     {
  306.         l=psamples[0];
  307.         r=psamples[1];
  308.         psamples+=2;
  309.         left_dcsum+=l;
  310.         left_rms+=l*l;
  311.         left_avg+=fabs(l);
  312.         if(l>left_maxlevelfound)
  313.         {
  314.             left_maxlevelfound=l;
  315.             time_left_maxvalue=dcnum;
  316.         }
  317.         if(l<left_minlevelfound)
  318.         {
  319.             left_minlevelfound=l;
  320.             time_left_minvalue=dcnum;
  321.         }
  322.         if(prev_left>=0)
  323.         {
  324.             if(l<0)
  325.             left_zerocross++;
  326.         } else
  327.         {
  328.             if(l>=0)
  329.             left_zerocross++;
  330.         }
  331.         tmp=fabs(l-prev_left);
  332.         if(tmp>left_max_change)
  333.         {
  334.             left_max_change=tmp;
  335.             time_left_change=dcnum;
  336.         }
  337.         prev_left=l;
  338.  
  339.         right_dcsum+=r;
  340.         right_rms+=r*r;
  341.         right_avg+=fabs(r);
  342.         if(r>right_maxlevelfound)
  343.         {
  344.             right_maxlevelfound=r;
  345.             time_right_maxvalue=dcnum;
  346.         }
  347.         if(r<right_minlevelfound)
  348.         {
  349.             right_minlevelfound=r;
  350.             time_right_minvalue=dcnum;
  351.         }
  352.         if(prev_right>=0)
  353.         {
  354.             if(r<0)
  355.             right_zerocross++;
  356.         } else
  357.         {
  358.             if(r>=0)
  359.             right_zerocross++;
  360.         }
  361.         tmp=fabs(r-prev_right);
  362.         if(tmp>right_max_change)
  363.         {
  364.             right_max_change=tmp;
  365.             time_right_change=dcnum;
  366.         }
  367.         prev_right=r;
  368.         dcnum++;
  369.     } while(--numsamples);
  370.     return true;
  371. }
  372.  
  373. bool mi::MDKWork(float *psamples, int numsamples, int const mode)
  374. {
  375.     float l;
  376.     double tmp;
  377.     if ((mode==WM_WRITE)||(mode==WM_NOIO))
  378.     {
  379.         return false;
  380.     }
  381.  
  382.     if (mode == WM_READ)        // <thru>
  383.         return true;
  384.  
  385.     do 
  386.     {
  387.         l=*psamples;
  388.         psamples++;
  389.         left_dcsum+=l;
  390.         left_rms+=l*l;
  391.         left_avg+=fabs(l);
  392.         if(l>left_maxlevelfound)
  393.         {
  394.             left_maxlevelfound=l;
  395.             time_left_maxvalue=dcnum;
  396.         }
  397.         if(l<left_minlevelfound)
  398.         {
  399.             left_minlevelfound=l;
  400.             time_left_minvalue=dcnum;
  401.         }
  402.         if(prev_left>=0)
  403.         {
  404.             if(l<0)
  405.             left_zerocross++;
  406.         } else
  407.         {
  408.             if(l>=0)
  409.             left_zerocross++;
  410.         }
  411.         tmp=fabs(l-prev_left);
  412.         if(tmp>left_max_change)
  413.         {
  414.             left_max_change=tmp;
  415.             time_left_change=dcnum;
  416.         }
  417.         prev_left=l;
  418.         dcnum++;
  419.     } while(--numsamples);
  420.     return true;
  421. }
  422.